package cn.demoncat.util.lang;

import cn.demoncat.util.exception.BizRuntimeException;
import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.entity.ListStr;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 树型级联ID工具(3段)
 * 
 * @author 延晓磊
 *
 * @since 2017年9月26日
 */
public final class TreeIdUtil {

	public static final int MIN_ID_SIZE = 3;
	public static final int MAX_ID_SIZE = 18;
	
	/**
	 * ID异常
	 */
	private static final String TREE_ID_ERROR = "编码必须是为100~999的1~{}组整数";
	/**
	 * 层级异常
	 */
	private static final String TREE_LEVEL_ERROR = "数据层级最大为";
	
	/**
	 * ID等级
	 * 
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年12月3日
	 */
	public static int getLevel(String id) {
		return id.length() / MIN_ID_SIZE;
	}
 
	/**
	 * ID等级
	 * 
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年12月3日
	 */
	public static int getLevel(Long id) {
		return (StringConstant.EMPTY + id).length() / MIN_ID_SIZE;
	}
	
	/**
	 * 获取特定层级的ID
	 *
	 * @param id
	 * @return 层级足够时截取，层级不够时返回null
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static String get(String id, int level) {
		if (check(id) && id.length() >= level * MIN_ID_SIZE) {
			return id.substring(0, level * MIN_ID_SIZE);
		}
		return null;
	}
	/**
	 * 获取特定层级的ID
	 *
	 * @param id
	 * @return 层级足够时截取，层级不够时返回null
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static String getNoCheck(String id, int level) {
		if (id.length() >= level * MIN_ID_SIZE) {
			return id.substring(0, level * MIN_ID_SIZE);
		}
		return null;
	}

	/**
	 * 获取父ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static String getParent(String id) {
		if (check(id)) {
			//1级
			if (id.length() == MIN_ID_SIZE) {
				return IDUtil.ROOT_ID;
			}
			return id.substring(0, id.length() - MIN_ID_SIZE);
		}
		return null;
	}
	/**
	 * 获取前辈ID集
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static List<String> getParents(String id) {
		List<String> list = new ArrayList<>();
		if (check(id)) {
			for (int i = id.length()/MIN_ID_SIZE; i > 1 ; i--) {
				list.add(id.substring(0, id.length() - MIN_ID_SIZE * (i-1)));
			}
		}
		return list;
	}
	
	/**
	 * 获取树ID集（级联ID）
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static ListStr getTrees(String id) {
		return StringUtil.splitTree(id, MIN_ID_SIZE);
	}
	
	/**
	 * 获取父ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static String getParentNoCheck(String id) {
		//1级
		if (id.length() == MIN_ID_SIZE) {
			return IDUtil.ROOT_ID;
		}
		return id.substring(0, id.length() - MIN_ID_SIZE);
	}
	/**
	 * 获取前辈ID集
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static List<String> getParentsNoCheck(String id) {
		List<String> list = new ArrayList<>();
		for (int i = id.length()/MIN_ID_SIZE; i > 1 ; i--) {
			list.add(id.substring(0, id.length() - MIN_ID_SIZE * (i-1)));
		}
		return list;
	}
	
	/**
	 * 获取树ID集（级联ID）
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static List<String> getTreesNoCheck(String id) {
		List<String> list = new ArrayList<>();
		for (int i = id.length()/MIN_ID_SIZE; i > 0 ; i--) {
			list.add(id.substring(0, id.length() - MIN_ID_SIZE * (i-1)));
		}
		return list;
	}
	
	/**
	 * 判断是否为特定层级的3段级联ID
	 *
	 * @param id
	 * @param level	层级
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean check(String id, int level) {
		// 3段级联ID; /3 = level
		return check(id) && id.length() / MIN_ID_SIZE == level;
	}
	
	/**
	 * 判断是否为特定层级的3段级联ID
	 *
	 * @param id
	 * @param level	层级
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean checkNoCheck(String id, int level) {
		// /3 = level
		return id.length() / MIN_ID_SIZE == level;
	}
	
	/**
	 * 判断是否为3段级联ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean check(String id){
		return checkNumId(id) && StringUtils.isNumeric(id);
	}
 
	/**
	 * 获取特定层级的ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static Long get(Long id, int level) {
		if (id != null) {
			// %3 == 0; <= 20*
			String idStr = id + StringConstant.EMPTY;
			if (checkNumId(idStr)) {
				return Long.valueOf(idStr.substring(0, level * MIN_ID_SIZE));
			}
		}
		return null;
	}
	/**
	 * 获取特定层级的ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static Long getNoCheck(Long id, int level) {
		return LongUtil.valueOf(getNoCheck(id+StringConstant.EMPTY, level));
	}

	/**
	 * 获取父ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static Long getParent(Long id) {
		return LongUtil.valueOf(getParent(id + StringConstant.EMPTY));
	}
 
	/**
	 * 获取前辈ID集
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static List<Long> getParents(Long id) {
		String idStr = id+StringConstant.EMPTY;
		List<Long> list = new ArrayList<>();
		if (check(idStr)) {
			for (int i = 1; i < idStr.length()/MIN_ID_SIZE; i++) {
				list.add(Long.valueOf(idStr.substring(0, idStr.length() - MIN_ID_SIZE*i)));
			}
		}
		return list;
	}
	/**
	 * 获取父ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static Long getParentNoCheck(Long id) {
		return LongUtil.valueOf(getParentNoCheck(id + StringConstant.EMPTY));
	}
	/**
	 * 获取前辈ID集
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static List<Long> getParentsNoCheck(Long id) {
		String idStr = id+StringConstant.EMPTY;
		List<Long> list = new ArrayList<>();
		for (int i = 1; i < idStr.length()/MIN_ID_SIZE; i++) {
			list.add(Long.valueOf(idStr.substring(0, idStr.length() - MIN_ID_SIZE*i)));
		}
		return list;
	}
	
	/**
	 * 判断是否为特定层级的3段级联ID
	 *
	 * @param id
	 * @param level	层级
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean check(Long id, int level) {
		if (id != null) {
			// %3 == 0; <= 20*; /3 = level
			String idStr = id + StringConstant.EMPTY;
			return checkNumId(idStr) && idStr.length() / MIN_ID_SIZE == level;
		}
		return false;
	}
	
	/**
	 * 判断是否为特定层级的3段级联ID
	 *
	 * @param id
	 * @param level	层级
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean checkNoCheck(Long id, int level) {
		return checkNoCheck(id+StringConstant.EMPTY, level);
	}
	
	/**
	 * 判断是否为3段级联ID
	 *
	 * @param id
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean check(Long id){
		if (id != null) {
			return checkNumId(id + StringConstant.EMPTY);
		}
		return false;
	}
	
	/**
	 * 检查ID格式
	 * 
	 * @param idStr
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年3月27日
	 */
	private static boolean checkNumId(String idStr) {
		// 3 <= size <= 20, size %3 = 0
		return !idStr.startsWith(StringConstant.N0) && idStr.length() >= MIN_ID_SIZE && idStr.length() <= MAX_ID_SIZE && idStr.length() % MIN_ID_SIZE == 0;
	}
	
	/**
	 * 校验ID参数
	 * 
	 * @param id	100-999，创建时主动拼接父级
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年3月13日
	 */
	public static void checkParam(String id) {
		if (!StringUtils.isNumeric(id) || !IntegerUtil.isRange(Integer.parseInt(id), 100, 999)) {
			throw new ParamRuntimeException("ID必须是100~999之间的整数");
		}
	}
	
	/**
	 * 判断级联层级
	 *
	 * @param id
	 * @param maxLevel	最大层级
	 * 
	 * @throws BizRuntimeException 层级错误
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static void checkLevel(String id, int maxLevel) {
		if (id.length() / MIN_ID_SIZE > maxLevel) {
			throw new BizRuntimeException(TREE_LEVEL_ERROR + maxLevel);
		}
	}
	
	/**
	 * 判断级联层级
	 *
	 * @param id
	 * @param maxLevel	最大层级
	 * 
	 * @throws BizRuntimeException 层级错误
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static void checkLevel(Long id, int maxLevel) {
		checkLevel(id.toString(),maxLevel);
	}
	
	/**
	 * 判断是否为级联ID
	 *
	 * @param id
	 * @param maxLevel	最大层级
	 * @return
	 * 
	 * @throws BizRuntimeException 编码错误
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean checkError(String id, int maxLevel) {
		// 3段级联ID; /3 = level
		if (check(id) && id.length() / MIN_ID_SIZE <= maxLevel) {
			return true;
		}
		throw new BizRuntimeException(StringUtil.logFormat(TREE_ID_ERROR, maxLevel));
	}
	
	/**
	 * 判断是否为级联ID
	 *
	 * @param id
	 * @param maxLevel	最大层级
	 * @return
	 * 
	 * @throws BizRuntimeException 编码错误
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年6月27日
	 */
	public static boolean checkError(Long id, int maxLevel) {
		if (id != null) {
			// %3 == 0; <= 20*; /3 = level
			String idStr = id + StringConstant.EMPTY;
			if (checkNumId(idStr) && idStr.length() / MIN_ID_SIZE <= maxLevel) {
				return true;
			}
		}
		throw new BizRuntimeException(StringUtil.logFormat(TREE_ID_ERROR, maxLevel));
	}
}
